#pragma once

//多生产多消费
#include <iostream>
#include <vector>
#include <ctime>
#include <semaphore.h>
#include <pthread.h>

const static int defaultcap=5;

template<class T>
class RingQueue
{
private:
    void P(sem_t &sem) //申请信号量
    {
        sem_wait(&sem);
    }

    void V(sem_t &sem) //发布信号量
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t &mutex) //加锁
    {
        pthread_mutex_lock(&mutex);
    }

    void Unlock(pthread_mutex_t &mutex) //解锁
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int capacity=defaultcap)
        :_ringqueue(capacity),_capacity(capacity),_c_step(0),_p_step(0)
    {
        sem_init(&_c_sem,0,0);
        sem_init(&_p_sem,0,capacity);

        pthread_mutex_init(&_c_mutex,nullptr);
        pthread_mutex_init(&_p_mutex,nullptr);
    }

    void Push(const T &in) //生产
    {
        P(_p_sem);

        Lock(_p_mutex); //先申请信号量，因为信号量是原子的
        _ringqueue[_p_step]=in;
        //向后移动，维持环形特性
        _p_step++;
        _p_step%=_capacity;
        Unlock(_p_mutex);

        V(_c_sem);
    }

    void Pop(T *out) //消费
    {
        P(_c_sem);

        Lock(_c_mutex);
        *out=_ringqueue[_c_step];
        //向后移动，维持环形特性
        _c_step++;
        _c_step%=_capacity;
        Unlock(_c_mutex);

        V(_p_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_c_sem);
        sem_destroy(&_p_sem);

        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);
    }

private:
    std::vector<T> _ringqueue; //环形队列
    int _capacity; //容量大小

    int _c_step; //消费者位置
    int _p_step; //生产者位置 

    sem_t _c_sem; //消费者信号量 关注的数据资源
    sem_t _p_sem; //生产者信号量 关注的空间资源

    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;
};

#if 0
//单生产单消费
#include <iostream>
#include <vector>
#include <ctime>
#include <semaphore.h>

const static int defaultcap=5;

template<class T>
class RingQueue
{
private:
    void P(sem_t &sem) //申请信号量
    {
        sem_wait(&sem);
    }

    void V(sem_t &sem) //发布信号量
    {
        sem_post(&sem);
    }

public:
    RingQueue(int capacity=defaultcap)
        :_ringqueue(capacity),_capacity(capacity),_c_step(0),_p_step(0)
    {
        sem_init(&_c_sem,0,0);
        sem_init(&_p_sem,0,capacity);
    }

    void Push(const T &in) //生产
    {
        P(_p_sem);
        _ringqueue[_p_step]=in;
        V(_c_sem);

        //向后移动，维持环形特性
        _p_step++;
        _p_step%=_capacity;
    }

    void Pop(T *out) //消费
    {
        P(_c_sem);
        *out=_ringqueue[_c_step];
        V(_p_sem);

        _c_step++;
        _c_step%=_capacity;
    }

    ~RingQueue()
    {
        sem_destroy(&_c_sem);
        sem_destroy(&_p_sem);
    }

private:
    std::vector<T> _ringqueue; //环形队列
    int _capacity; //容量大小

    int _c_step; //消费者位置
    int _p_step; //生产者位置 

    sem_t _c_sem; //消费者信号量 关注的数据资源
    sem_t _p_sem; //生产者信号量 关注的空间资源
};
#endif 